﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Tile_Engine;

namespace AGrandVenture.Dungen
{
    public enum DirectionType
    {
        North,
        South,
        East,
        West,
        Up,
        Down,
        None
    }

    public static class DungeonGenerator
    {
        private static int numOfPlacedRooms = 0;

        private static int[,] Map; //level layout
        private static int MapWidth = 0;
        private static int MapHeight = 0;

        private static int minRoomSize = 2;
        private static int maxRoomSize = 8;

        private static Random random;

        private static DirectionType currentBuildDirection = DirectionType.None;

        public static int[,] GetMap
        {
            get { return Map; }
        }

        public static void Initialise(int width, int height)
        {
            int seed = DateTime.Now.Millisecond;
            random = new Random(seed);

            MapWidth = width;
            MapHeight = height;

            InitMap(width, height);
        }

        public static void InitMap(int width, int height)
        {
            Map = new int[height, width];
            FillMap(1); // fills map with solid
        }

        public static void FillMap(int TileType)
        {
            for (int x = 0; x < MapWidth; x++)
                for (int y = 0; y < MapHeight; y++)
                    Map[y, x] = TileType;
        }

        public static int[,] MakeRoom(int width, int height)
        {
            int[,] room = new int[width, height];
            for (int x = 0; x < width; x++)
                for (int y = 0; y < height; y++)
                    room[x, y] = 0;
            return room;
        }

        public static void PlaceRoom(int mapX, int mapY, int[,] room)
        {
            for (int x = 0; x <= room.GetUpperBound(0); x++)
                for (int y = 0; y <= room.GetUpperBound(1); y++)
                    Map[mapX + x, mapY + y] = room[x, y];

            numOfPlacedRooms++;
        }

        public static void PlaceDoor(int x, int y)
        {
            Map[x, y] = 0;
        }

        private static void PlaceStartRoom()
        {
            PlaceRoom(MapWidth / 2, MapHeight / 2, MakeRoom(4, 4));
        }

        private static int PickRandomXTile()
        {
            return random.Next(0, MapWidth);
        }

        private static int PickRandomYTile()
        {
            return random.Next(0, MapHeight);
        }

        private static void FindNextBuildPoint()
        {
            int x = PickRandomXTile();
            int y = PickRandomYTile();
            bool canPlace = false;

            if (Map[x, y] == 0)
            {
                if (adjacentToWall(x, y))
                {
                    DirectionType direction = getDirectionToBuild(x, y);

                    int[,] room = MakeRoom(random.Next(minRoomSize, maxRoomSize), random.Next(minRoomSize, maxRoomSize));


                    switch (direction)
                    {
                        case DirectionType.North:
                            y = y - 1 - room.GetLength(1);
                            canPlace = canBePlaced(x, y, room);
                            break;
                        case DirectionType.South:
                            y = y + 2;
                            canPlace = canBePlaced(x, y, room);
                            break;
                        case DirectionType.East:
                            x = x + 2;
                            canPlace = canBePlaced(x, y, room);
                            break;
                        case DirectionType.West:
                            x = x - 1 - room.GetLength(0);
                            canPlace = canBePlaced(x, y, room);
                            break;
                        case DirectionType.Up:
                            break;
                        case DirectionType.Down:
                            break;
                        case DirectionType.None:
                            Console.Write("Direction.None Returned in FindNextBuildPoint!");
                            break;
                        default:
                            break;
                    }
                    if (canPlace)
                    {
                        switch (direction)
                        {
                            case DirectionType.North:
                                PlaceDoor(x, y + room.GetLength(1));
                                break;
                            case DirectionType.South:
                                PlaceDoor(x, y - 1);
                                break;
                            case DirectionType.East:
                                PlaceDoor(x - 1, y);
                                break;
                            case DirectionType.West:
                                PlaceDoor(x + room.GetLength(0), y);
                                break;
                            case DirectionType.Up:
                                break;
                            case DirectionType.Down:
                                break;
                            case DirectionType.None:
                                break;
                            default:
                                break;
                        }
                        Console.WriteLine(direction.ToString() + room.GetLength(0).ToString() + room.GetLength(1).ToString());
                        PlaceRoom(x, y, room);
                    }
                }
            }
            else
                FindNextBuildPoint();
        }

        private static bool canBePlaced(int mapX, int mapY, int[,] room)
        {
            for (int x = 0; x <= room.GetUpperBound(0); x++)
                for (int y = 0; y <= room.GetUpperBound(1); y++)
                    if (Map[mapX + x, mapY + y] != 1)
                        return false;

            return true;
        }

        private static DirectionType getDirectionToBuild(int x, int y)
        {
            //check right
            if (Map[x + 1, y] == 1)
                return DirectionType.East;
            //check left
            if (Map[x - 1, y] == 1)
                return DirectionType.West;
            //check top
            if (Map[x, y - 1] == 1)
                return DirectionType.North;
            //check bottom
            if (Map[x, y + 1] == 1)
                return DirectionType.South;

            return DirectionType.None;
        }

        private static bool adjacentToWall(int x, int y)
        {
            //check right
            if (Map[x + 1, y] == 1)
            {

                return true;
            }
            //check left
            if (Map[x - 1, y] == 1)
            {
                return true;
            }
            //check top
            if (Map[x, y - 1] == 1)
            {
                return true;
            }
            //check bottom
            if (Map[x, y + 1] == 1)
            {
                return true;
            }

            return false;

        }

        public static void AddMonsterGenerators(int numberofGenerators)
        {
            int count = 0;

            

            while (count <= numberofGenerators)
            {
                int x = PickRandomXTile();
                int y = PickRandomYTile();

                if(Map[x,y] == 0)
                {
                    TileMap.GetMapSquareAtCell(x, y).CodeValue = "ENEMY";
                    count++;
                }
                        
            }
        }

        public static void AddChests(int numberofChests)
        {
            int count = 0;



            while (count <= numberofChests)
            {
                int x = PickRandomXTile();
                int y = PickRandomYTile();

                if (Map[x, y] == 0)
                {
                    TileMap.GetMapSquareAtCell(x, y).CodeValue = "CHEST";
                    count++;
                }

            }
        }

        public static void MakeLevel()
        {
            PlaceStartRoom();

            while (numOfPlacedRooms != 38)
                FindNextBuildPoint();
        }

    }
}
